#if (FEATURE_MODE == 0)
/**
 @file sys_usw_dot1ae.h

 @date 2010-2-26

 @version v2.0

---file comments----
*/

#ifndef SYS_USW_DOT1AE_H_
#define SYS_USW_DOT1AE_H_
#ifdef __cplusplus
extern "C" {
#endif

/***************************************************************
 *
 * Header Files
 *
 ***************************************************************/
#include "sal.h"
#include "ctc_const.h"
#include "ctc_dot1ae.h"
#include "ctc_l2.h"
#include "sys_usw_register.h"
#include "sys_usw_mchip.h"



/***************************************************************
 *
 *  Defines and Macros
 *
 ***************************************************************/
#define SYS_DOT1AE_PACKET_MAX_LENTH   0x3FFF
#define SYS_DOT1AE_SCI_LEN 8
#define SYS_USW_DOT1AE_GPORT_IS_REMOTE(lchip,gport) (SYS_GCHIP_IS_REMOTE(lchip, SYS_MAP_CTC_GPORT_TO_GCHIP(gport)))

#define SYS_DOT1AE_DBG_OUT(level, FMT, ...) \
    do { \
        CTC_DEBUG_OUT(dot1ae, dot1ae, DOT1AE_SYS, level, FMT, ##__VA_ARGS__); \
    } while (0);

#define SYS_DOT1AE_INIT_CHECK(lchip) \
    do \
    { \
        LCHIP_CHECK(lchip); \
        if (usw_dot1ae_master[lchip] == NULL){ \
            SYS_DOT1AE_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " Feature not initialized \n");\
            return CTC_E_NOT_INIT;} \
    } while (0)


#define SYS_DOT1AE_CREATE_LOCK(lchip)                   \
    do                                            \
    {                                             \
        sal_mutex_create(&usw_dot1ae_master[lchip]->sec_mutex); \
        if (NULL == usw_dot1ae_master[lchip]->sec_mutex)  \
        { \
            CTC_ERROR_RETURN(CTC_E_NO_MEMORY); \
        } \
    } while (0)

#define SYS_DOT1AE_LOCK(lchip) \
    if (usw_dot1ae_master[lchip]->sec_mutex) sal_mutex_lock(usw_dot1ae_master[lchip]->sec_mutex)

#define SYS_DOT1AE_UNLOCK(lchip) \
    if (usw_dot1ae_master[lchip]->sec_mutex) sal_mutex_unlock(usw_dot1ae_master[lchip]->sec_mutex)

#define SYS_DOT1AE_REVERSE(dest, src, len)      \
{                                            \
    int32 i = 0;                             \
    for (i=0;i<(len);i++)                    \
    {                                        \
        (dest)[(len)-1-i] = (src)[i];          \
    }                                        \
}
#define SYS_DOT1AE_32var_TO_64var(dest, high32, low32)    \
{\
    sal_memcpy(&(dest), &(high32), sizeof(uint32));\
    sal_memcpy((uint8 *)&(dest) + sizeof(uint32), &(low32), sizeof(uint32));\
}
#define SYS_DOT1AE_GPORT_TO_PP_ID(gport)   (CTC_MAP_GPORT_TO_LPORT(gport)/48)

#define SYS_DOT1AE_FOREACH_DP_BEGIN(dp_bmp)  \
{\
  uint8 dp_idx=0;  \
for(dp_idx =0;dp_idx<2;dp_idx++) \
{ \
   if(CTC_IS_BIT_SET(dp_bmp, dp_idx)) \
    {

#define SYS_DOT1AE_FOREACH_DP_END  \
} \
}\
}

#define SYS_DOT1AE_ENTRY_HASH_NOT_EXIST(lchip, type, entry_id, pp_bmp)    \
{\
    if (CTC_E_NONE == sys_usw_dot1ae_lookup_entry_hash(lchip, entry_id, type, &pp_bmp)) {return CTC_E_EXIST;}\
}
#define SYS_DOT1AE_ENTRY_HASH_ENTRY_EXIST(lchip, type, entry_id, pp_bmp)    \
{\
    if (CTC_E_NONE != sys_usw_dot1ae_lookup_entry_hash(lchip, entry_id, type, &pp_bmp)) {return CTC_E_NOT_EXIST;}\
}

struct sys_dot1ae_chan_bind_node_s
{
    ctc_slistnode_t head;
    uint32 value;
};
typedef struct sys_dot1ae_chan_bind_node_s sys_dot1ae_chan_bind_node_t;
struct sys_dot1ae_sa_config_s
{
    uint64 next_pn;
    uint8  key[CTC_DOT1AE_KEY_LEN];
    uint8  salt[CTC_DOT1AE_SALT_LEN];
    uint32 ssci;
    uint64 lowest_pn;
    uint32 an             :2,
           cipher_mode    :3,
           cipher_suite   :2,
           no_encryption  :1,
           ebit_cbit      :1,
           validateFrames :2,
           icv_discard    :1,
           icv_exception  :1,
           rsv            :19;
};
typedef struct sys_dot1ae_sa_config_s sys_dot1ae_sa_config_t;

typedef struct
{
    ds_t key;
    ds_t action;
}sys_dot1ae_buffer_t;

struct sys_dot1ae_entry_s
{
    uint32 entry_id;

    uint32 key_type :3;              /* refer to ctc_dot1ae_key_type_t */
    uint32 dir:1;                    /* ingress is decrypt, egress is encrypt, refer to ctc_direction_t; */
    uint32 dp_bmp:2;
    uint32 rsv:26;

    uint8 sc_index[2];              /* sec_chan index, 0-127 */
    uint8 is_cam[2];                 /* when hash key is conflict, use cam table, acc return is_cam */
    uint16 hash_key_index[2];        /* index to key table, 0-511 */
    uint32 gport;
    uint32 chan_id;

};
typedef struct sys_dot1ae_entry_s sys_dot1ae_entry_t;


struct sys_dot1ae_show_entry_info_s
{
    uint8 type ;
	uint8 dir;
	uint8 key_type;
	uint8 detail;
	uint32 entry_id;
};
typedef struct sys_dot1ae_show_entry_info_s sys_dot1ae_show_entry_info_t;
enum sys_dot1ae_bind_type_e
{
    SYS_DOT1AE_BIND_TYPE_PORT = 0,      /**< [D2.TM.TMM.AT] bind dot1ae sec channel on port,  used for macsec*/
    SYS_DOT1AE_BIND_TYPE_NEXTHOP = 1,   /**< [TMM] bind dot1ae sec channel on nexthop, [TMM] used for cloudsec encrypt*/
    SYS_DOT1AE_BIND_TYPE_LOGICPORT = 2, /**< [TMM] bind dot1ae sec channel on logic port, [TMM] used for cloudsec decrypt*/
    SYS_DOT1AE_BIND_TYPE_ENTRY = 3,      /**< [AT] bind dot1ae sec channel with entry */
    SYS_DOT1AE_BIND_TYPE_MAX
};
typedef enum sys_dot1ae_bind_type_e sys_dot1ae_bind_type_t;

struct sys_tm_dot1ae_an_stats_s
{
    uint64 out_pkts_protected;      /**< protected packet count*/
    uint64 out_pkts_encrypted;      /**< encrypted packet count*/
    uint64 in_pkts_ok;              /**< valid packet count*/
    uint64 in_pkts_unchecked;       /**< unchecked packet count*/
    uint64 in_pkts_delayed;         /**< delayed packet count*/
    uint64 in_pkts_invalid;         /**< invalid packet count*/
    uint64 in_pkts_not_valid;       /**< not valid packet count*/
    uint64 in_pkts_late;            /**< late packet count*/

    /*In p2mp mode,the following statsics are bound the port, so itcan be got through
    the API ctc_port_get_direction_property(CTC_PORT_DIR_PROP_DOT1AE_STATS) */
    uint64 in_pkts_not_using_sa;    /**<  not using sa packet count*/
    uint64 in_pkts_unused_sa;       /**<  unused sa packet count*/
};
typedef struct sys_tm_dot1ae_an_stats_s sys_tm_dot1ae_an_stats_t;

struct sys_tmm_dot1ae_an_stats_s
{
    uint64 out_pkts_protected;      /**< protected packet count*/
    uint64 out_pkts_encrypted;      /**< encrypted packet count*/
    uint64 in_pkts_ok;              /**< valid packet count*/
    uint64 in_pkts_unchecked;       /**< unchecked packet count*/
    uint64 in_pkts_delayed;         /**< delayed packet count*/
    uint64 in_pkts_invalid;         /**< invalid packet count*/
    uint64 in_pkts_not_valid;       /**< not valid packet count*/
    uint64 in_pkts_late;            /**< late packet count*/
    uint64 out_pkts_sa_not_inuse;   /**< packet not using sa packet count*/

    /*In p2mp mode,the following statsics are bound the port, so itcan be got through
    the API ctc_port_get_direction_property(CTC_PORT_DIR_PROP_DOT1AE_STATS) */
    uint64 in_pkts_not_using_sa;    /**< not using sa packet count*/
    uint64 in_pkts_unused_sa;       /**< unused sa packet count*/
    uint64 in_pkts_badtag;          /**< badtag packet count*/
    uint64 in_octets_decrypted;     /**< decrypted octets count*/
    uint64 in_octets_validated;     /**< validated octets count, not decrypted but passed icvcheck*/
    uint64 out_pkts_toolong;        /**< packet lenth too long count*/
    uint64 out_pkts_untagged;       /**< packet without macsectag count*/
    uint64 out_octets_encrypted;    /**< encrypted octets count*/
    uint64 out_octets_protected;    /**< validated octets count, not encrypted  but icvcheck*/

};
typedef struct sys_tmm_dot1ae_an_stats_s sys_tmm_dot1ae_an_stats_t;

struct sys_at_dot1ae_an_stats_s
{
    uint64 out_pkts_protected;      /**< protected packet count*/
    uint64 out_pkts_encrypted;      /**< encrypted packet count*/
    uint64 in_pkts_ok;              /**< valid packet count*/
    uint64 in_pkts_unchecked;       /**< unchecked packet count*/
    uint64 in_pkts_delayed;         /**< delayed packet count*/
    uint64 in_pkts_invalid;         /**< invalid packet count*/
    uint64 in_pkts_not_valid;       /**< not valid packet count*/
    uint64 in_pkts_late;            /**< late packet count*/
    uint64 out_pkts_sa_not_inuse;   /**< [TMM] packet not using sa packet count*/

    /*In p2mp mode,the following statsics are bound the port, so itcan be got through
    the API ctc_port_get_direction_property(CTC_PORT_DIR_PROP_DOT1AE_STATS) */
    uint64 in_pkts_not_using_sa;    /**< not using sa packet count*/
    uint64 in_pkts_unused_sa;       /**< unused sa packet count*/
    uint64 in_pkts_badtag;          /**< badtag packet count*/
    uint64 in_octets_decrypted;     /**< decrypted octets count*/
    uint64 in_octets_validated;     /**< validated octets count, not decrypted but passed icvcheck*/
    uint64 out_pkts_toolong;        /**< packet lenth too long count*/
    uint64 out_pkts_untagged;       /**< packet without macsectag count*/
    uint64 out_octets_encrypted;    /**< encrypted octets count*/
    uint64 out_octets_protected;    /**< validated octets count, not encrypted  but icvcheck*/
    uint64 out_pkts_uncontrol_port; /**< packet lenth too long count*/
};
typedef struct sys_at_dot1ae_an_stats_s sys_at_dot1ae_an_stats_t;


struct sys_dot1ae_chan_s
{
    uint32 chan_id;
    uint32  dir:1,
            valid:1,
            include_sci:1,
            an_en:4,/*an inuse*/
            next_an:4,/**/
            an_valid:4,/*valid an cfg*/
            binding_type:2, /* refer to sys_dot1ae_bind_type_t */
            replayProtect:1,
            validateFrames:2,
            macsecType:1,
            dp_bmp:2,
            dp_id:2,
            rsv:7;
    uint32  p2mp:1,
            scl_id:2,/*p2mp scl_id */
            enable:1, /*p2mp enable*/
            alloced_source:1,
            is_xpn:1,
            pn_mode:2,
            clear_tag_en:1,
            binded:1,
            clear_tag_type:2,
            pp_id:4,
            is_udp:1,
            protocol_type:1,
            with_ctc_sh:1,
            is_use_plain:1,/* AT, sec_chan is use for packet bypass decryption */
            rsv2:12;
    uint16 ref_cnt[2];
    uint8  sc_index[2];
    uint32 gport;
    ctc_slist_t* bind_mem_list;
    uint8  *key;   /*only for duet2*/
    uint32 replayProtectWindow;
    uint8 *sci;
    sys_dot1ae_sa_config_t* sa_cfg;/*TMM..*/
    void* an_stats;/* Arctic:sys_at_dot1ae_an_stats_t, TsingMa_Mx:sys_tmm_dot1ae_an_stats_t, Tsingma: sys_tm_dot1ae_an_stats_t */
};
typedef struct sys_dot1ae_chan_s sys_dot1ae_chan_t;
struct sys_dot1ae_bind_chan_s
{
    uint32* p_chan_id;
    uint32 count;
    uint8 dir;
    uint8 p2mp;
};
typedef struct sys_dot1ae_bind_chan_s sys_dot1ae_bind_chan_t;
struct sys_dot1ae_global_stats_s
{
    uint64 in_pkts_no_sci;                 /**< [TM] Dot1AE global stats*/
    uint64 in_pkts_unknown_sci;            /**< [TM] Dot1AE global stats*/
};
typedef struct sys_dot1ae_global_stats_s sys_dot1ae_global_stats_t;

struct sys_dot1ae_maskbmp_s
{
    uint32 mask_bitmap;

    uint32  calc_key_len[0];

    ctc_spool_index_t index;
};
typedef struct sys_dot1ae_maskbmp_s sys_dot1ae_maskbmp_t;

struct sys_dot1ae_master_s
{
    uint8  dot1ae_opf_type;
    uint8 is_xpn;
    uint8  rsv[2];
    sal_mutex_t* sec_mutex;
    sys_dot1ae_global_stats_t global_stats;
    ctc_hash_t*  chan_hash;
    uint32 dp0_rx_bmp[4];
    uint32 dp0_tx_bmp[4];
    uint32 dp1_rx_bmp[4];
    uint32 dp1_tx_bmp[4];
    ctc_hash_t*  entry_hash;
    ctc_hash_t*  pp_hash;
    void* entry_hash_db;/*pointer to ctc_at_dot1ae_master*/
    ctc_spool_t* dp0_rx_spool;  /**< [AT] manage DP0 decryption maskBitmap */
    ctc_spool_t* dp0_tx_spool;  /**< [AT] manage DP0 encryption maskBitmap */
    ctc_spool_t* dp1_rx_spool;  /**< [AT] manage DP1 decryption maskBitmap */
    ctc_spool_t* dp1_tx_spool;  /**< [AT] manage DP1 encryption maskBitmap */
};
typedef struct sys_dot1ae_master_s sys_dot1ae_master_t;
extern sys_dot1ae_master_t* usw_dot1ae_master[CTC_MAX_LOCAL_CHIP_NUM_PP] ;

/*Note: If segtag is not 12, cipher_mode must choose 4 or 5*/
enum sys_dot1ae_cipher_mode_e
{
    SYS_DOT1AE_ENCRYPT_OFFSET_0, /*calculate icv + decrypt all user data*/
    SYS_DOT1AE_ENCRYPT_OFFSET_30,  /*calculate icv + decrypt user data after 30 bytes*/
    SYS_DOT1AE_ENCRYPT_OFFSET_50,  /*calculate icv + decrypt user data after 50 bytes*/
    SYS_DOT1AE_ICV_CAL_OFFSET_0,   /*calculate icv only,but not decrypt user data*/
    SYS_DOT1AE_ENCRYPT_OFFSET_FROM_TAG,  /*calculate icv + decrypt all user data, icv calculate not inclue header before SegTag*/
    SYS_DOT1AE_ICV_CAL_OFFSET_FROM_TAG    /*calculate icv only, and not decrypt user data, icv calculate not inclue header before SegTag*/
};
typedef enum sys_dot1ae_cipher_mode_e sys_dot1ae_cipher_mode_t;


/***************************************************************
 *
 *  Functions
 *
 ***************************************************************/
extern int32
sys_usw_dot1ae_init(uint8 lchip);
extern int32
sys_usw_dot1ae_deinit(uint8 lchip);
extern int32
sys_usw_dot1ae_add_sec_chan(uint8 lchip, ctc_dot1ae_sc_t* p_chan);

extern int32
sys_usw_dot1ae_remove_sec_chan(uint8 lchip,ctc_dot1ae_sc_t* p_chan);

extern int32
sys_usw_dot1ae_update_sec_chan(uint8 lchip, ctc_dot1ae_sc_t* p_chan);

extern int32
sys_usw_dot1ae_get_sec_chan(uint8 lchip, ctc_dot1ae_sc_t* p_chan);

extern int32
sys_usw_dot1ae_set_global_cfg(uint8 lchip, ctc_dot1ae_glb_cfg_t* p_glb_cfg);

extern int32
sys_usw_dot1ae_get_global_cfg(uint8 lchip, ctc_dot1ae_glb_cfg_t* p_glb_cfg);

extern int32
sys_usw_dot1ae_bind_sec_chan(uint8 lchip, void* p_bind_sc);

extern int32
sys_usw_dot1ae_unbind_sec_chan(uint8 lchip, void* p_bind_sc);
extern int32
sys_usw_dot1ae_get_bind_sec_chan(uint8 lchip, void* p_bind_sc);

extern int32
sys_usw_dot1ae_get_stats(uint8 lchip, uint32 chan_id, ctc_dot1ae_stats_t* p_stats);

extern int32
sys_usw_dot1ae_clear_stats(uint8 lchip, uint32 chan_id, uint8 an);

extern int32
sys_usw_dot1ae_add_entry(uint8 lchip, ctc_dot1ae_entry_t* p_ctc_entry);
extern int32
sys_usw_dot1ae_remove_entry(uint8 lchip, uint32 entry_id);
extern int32
sys_usw_dot1ae_show_entry(uint8 lchip, sys_dot1ae_show_entry_info_t* param);
extern int32
sys_usw_dot1ae_get_entry(uint8 lchip,uint32 entry_id);
extern int32
sys_usw_dot1ae_register_entry_hash_db(uint8 lchip, void* user_data);
extern int32
sys_usw_dot1ae_set_hash_field_sel(uint8 lchip, ctc_dot1ae_hash_sel_t* p_hash_sel);
extern int32
sys_usw_dot1ae_get_hash_field_sel(uint8 lchip, ctc_dot1ae_hash_sel_t* p_hash_sel);
extern sys_dot1ae_entry_t*
sys_usw_dot1ae_lkup_entry(uint8 lchip,uint32 entry_id);
extern int32
sys_usw_dot1ae_lookup_entry_hash(uint8 lchip, uint32 entry_id, uint8 type, uint16* pp_bmp);
extern int32
sys_usw_dot1ae_add_entry_hash(uint8 lchip, uint32 entry_id, uint16 pp_bmp, uint8 type);
extern int32
sys_usw_dot1ae_remove_entry_hash(uint8 lchip, uint32 entry_id);


#ifdef __cplusplus
}
#endif

#endif

#endif

